package com.ellecity06.common.http

import android.app.Dialog
import androidx.fragment.app.Fragment
import androidx.lifecycle.LifecycleCoroutineScope
import androidx.lifecycle.LifecycleOwner
import androidx.lifecycle.lifecycleScope
import androidx.lifecycle.viewModelScope
import com.ellecity06.common.base.BaseViewModel
import com.ellecity06.common.base.view.LoadUiIntent
import com.ellecity06.common.helper.LoginHelper
import com.ellecity06.common.helper.NetworkHelper
import com.ellecity06.common.http.entity.ApiResponse
import com.ellecity06.common.http.exception.ApiException
import com.ellecity06.common.http.exception.ExceptionHandle
import com.ellecity06.common.http.exception.HttpErrorException
import com.ellecity06.common.utils.ToastUtils
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.flow.catch
import kotlinx.coroutines.flow.flow
import kotlinx.coroutines.flow.flowOn
import kotlinx.coroutines.flow.onCompletion
import kotlinx.coroutines.flow.onStart
import kotlinx.coroutines.launch

/**
 * @author ellecity06
 * @time 2023/4/12 17:40
 * @des
 */
/**
 * 列表类型的请求，主要用于区分开列表和非列表的请求处理
 */
const val GLOBAL_REQUEST_TYPE_LIST = 0x01
const val GLOBAL_REQUEST_TYPE_DEFAULT = 0x00

/**
 * 发起HTTP请求
 * @param body 请求的主体
 * @param success 请求成功的回调
 * @param fail 请求成功，但是接口响应的失败的回调
 * @param error 请求失败，主要是HTTP层面的失败
 * @param tokenExpired token过期的回调
 * @param showLoading 是否显示loading
 * @param cancelable loading能否取消 ,取消的时候会取消请求
 * @param requestId 当前请求的唯一ID
 */
fun <T> BaseViewModel.launchFlow(
    body: suspend CoroutineScope.() -> ApiResponse<T>,
    success: suspend (T?) -> Unit = {},
    showLoading: Boolean = true,
    loadText: String = "加载中...",
    tokenExpired: ((String) -> Unit)? = {
        sendLoadUiIntent(LoadUiIntent.AuthorizationExpired(it))
    },
    error: suspend (Throwable) -> Unit = { t ->
        //默认异常处理，子类可以进行覆写
        sendLoadUiIntent(LoadUiIntent.Error(t.message ?: "系统异常"))
    }
) {
    viewModelScope.launch {
        flow {
            if (!NetworkHelper.isNetworkConnected()) {
                throw HttpErrorException(message = "当前网络不可用")
            } else {
                emit(body())
            }
        }.flowOn(Dispatchers.IO)
            .onStart {
                if (showLoading)
                    sendLoadUiIntent(LoadUiIntent.Loading(text = loadText, true))
            }.catch {
                val exception = ExceptionHandle.handleException(e = it)
                error.invoke(exception)
            }.onCompletion {
                if (showLoading) sendLoadUiIntent(LoadUiIntent.Loading(text = loadText, false))
            }.collect { response ->
                if (response.isSuccess) {
                    success.invoke(response.data)
                } else {
                    if (response.tokenExpired) {
                        if (tokenExpired != null) {
                            tokenExpired.invoke(response.msg ?: "登录失效了，请重新登录！")
                        } else {
                            tokenExpired(response.msg ?: "登录失效了，请重新登录！")
                        }

                    } else {
                        error.invoke(ApiException(response.msg ?: "数据异常", response.code ?: -1))
                    }
                }
            }
    }

}

fun <T> CoroutineScope.launchFlow(
    body: suspend CoroutineScope.() -> ApiResponse<T>,
    success: suspend (T?) -> Unit = {},
    loadText: String = "加载中...",
    tokenExpired: ((String) -> Unit)? = {

    },
    loading: Dialog? = null,
    error: suspend (Throwable) -> Unit = { t ->
        //默认异常处理，子类可以进行覆写
        ToastUtils.show(t.message ?: "系统异常")
    }
) {
   launch {
        flow {
            if (!NetworkHelper.isNetworkConnected()) {
                throw HttpErrorException(message = "当前网络不可用")
            } else {
                emit(body())
            }
        }.flowOn(Dispatchers.IO)
            .onStart {
                loading?.show()
            }.catch {
                val exception = ExceptionHandle.handleException(e = it)
                error.invoke(exception)
            }.onCompletion {
                loading?.dismiss()
            }.collect { response ->
                if (response.isSuccess) {
                    success.invoke(response.data)
                } else {
                    if (response.tokenExpired) {
                        tokenExpired?.invoke(response.msg ?: "登录失效了，请重新登录！")

                    } else {
                        error.invoke(ApiException(response.msg ?: "数据异常", response.code ?: -1))
                    }
                }
            }
    }

}